/*
 * @Author: “ygnnli” “1585923072@qq.com”
 * @Date: 2024-08-09 15:16:03
 * @LastEditors: “ygnnli” “1585923072@qq.com”
 * @LastEditTime: 2024-08-10 10:29:20
 * @FilePath: /83/Reactor/Reactor.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <unordered_map>
#include "Connection.hpp"
#include "Epoller.hpp"

// TcpServer -> rename
// TcpServer: 对于已经就绪的事件，进行通知！
// 这个tcpserver提供_connections的管理工作
// TcpServer就是Reactor(反应堆)
// 事件派发器
class Reactor
{
    static const int gnum = 64; // 事件数组大小

public:
    Reactor() : _isrunning(false)
    {
    }

    void AddConnection(int fd, uint32_t event, func_t recver, func_t sender, func_t excepter)
    {
        // 1.构建Connection对象
        Connection *conn = new Connection(fd);
        conn->SetEvents(event);                   // 设置关心事件
        conn->Register(recver, sender, excepter); // 注册回调函数
        conn->SetSelf(this);

        // 2.向内核中设定fd关心的事件
        _epoller.AddEvent(conn->Sockfd(), conn->Events()); // 将文件描述符和关心事件注册到epoller中

        // 3.向_connections中添加connection对象
        _connections.insert(std::make_pair(conn->Sockfd(), conn)); // 将connection对象添加到map中
    }

    void EnableReadWrite(int sockfd, bool readable, bool writable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writable ? EPOLLOUT : 0) | EPOLLET; // 设置关心的事件
        if (ConnectionIsExists(sockfd))                                                   // 如果文件描述符存在
        {
            // 1.修改关心的事件
            _connections[sockfd]->SetEvents(events);

            // 2.修改内核关心的事件
            _epoller.ModEvent(sockfd, events);
        }
    }

    void RemoveConnection(int sockfd)
    {
        if (!ConnectionIsExists(sockfd))
            return; // 如果文件描述符不存在，直接返回
        // 1. 去掉epoll对该文件fd的关心
        _epoller.DelEvent(sockfd);
        // 2. 服务器端也要关闭sockfd
        _connections[sockfd]->Close();
        // 3. 释放connection
        delete _connections[sockfd]; // 释放connection对象
        // 4. 从_connections中删除
        _connections.erase(sockfd); // 从sock从map中删除
    }

    bool ConnectionIsExists(int sockfd)
    {
        auto iter = _connections.find(sockfd); // 查找文件描述符
        return iter != _connections.end();     // 返回是否找到
    }

    // 一次循环
    void LoopOnce(int timeout)
    {
        int n = _epoller.Wait(_revs, gnum, timeout);
        for (int i = 0; i < n; ++i)
        {
            int sockfd = _revs[i].data.fd;      // 获取文件描述符
            uint32_t revents = _revs[i].events; // 获取事件

            // 异常
            if (revents & EPOLLHUP)              // 对方关闭连接
                revents |= (EPOLLIN | EPOLLOUT); // 将读和写事件都加上
            if (revents & EPOLLERR)              // 错误事件
                revents |= (EPOLLIN | EPOLLOUT); // 将读和写事件都加上
            if (revents & EPOLLIN)               // 读事件
            {
                if (ConnectionIsExists(sockfd) && (_connections[sockfd]->_recver != nullptr))
                {
                    _connections[sockfd]->_recver(_connections[sockfd]); // 调用回调函数
                }
            }
            if (revents & EPOLLOUT) // 写事件
            {
                if (ConnectionIsExists(sockfd) && (_connections[sockfd]->_sender != nullptr))
                {
                    _connections[sockfd]->_sender(_connections[sockfd]); // 调用回调函数
                }
            }
        }
    }

    // 事件派发核心函数
    void Dispatcher()
    {
        _isrunning = true;
        int timeout = 3000; // 3秒阻塞等待
        while (_isrunning)
        {
            LoopOnce(timeout); // 一次循环
            Debug();//打印
        }
        _isrunning = false;
    }

    void Debug()
    {
        std::cout << "-------------------------------------" << std::endl;

        for (auto &connection : _connections)
        {
            std::cout << "fd: " << connection.second->Sockfd() << ", "; // 文件描述符
            uint32_t events = connection.second->Events();              // 事件获取事件
            if ((events & EPOLLIN) && (events & EPOLLET))
            {
                std::cout << "EPOLLIN | EPOLLET, " << std::endl;
            }
            if ((events & EPOLLOUT) && (events & EPOLLET))
            {
                std::cout << "EPOLLOUT | EPOLLET, " << std::endl;
            }
        }

        std::cout << "-------------------------------------" << std::endl;
    }

    ~Reactor()
    {
    }

private:
    std::unordered_map<int, Connection *> _connections; // 文件描述符
    Epoller _epoller;                                   //
    bool _isrunning;                                    // 是否运行

    struct epoll_event _revs[gnum]; // 事件数组
};